#include "Factory.h"
#include "Multigrid.h"
#include <string>
#include <iostream>
#include <memory>
#include <tuple>

using namespace std;

//Factory<AbstractMultigrid, tuple<int, string, string, string>, shared_ptr<AbstractMultigrid>(*)()> MultigridFactory;
typedef SingletonHolder<Factory<AbstractMultigrid, tuple<int, string, string, string> > > MultigridFactory;

namespace
{
	template
	<
		int DIM, 
		template <int, template <int> class, template <int> class> class Cycle = VCycle,
		template <int> class Restriction = FullWeighting,
		template <int> class Interpolation = Linear
	>
	shared_ptr<AbstractMultigrid> CreateMultigrid()
	{
		return shared_ptr<Multigrid<DIM, Cycle, Restriction, Interpolation> >(new Multigrid<DIM, Cycle, Restriction, Interpolation>);
	}
}

void Register()
{
	const bool register1 = MultigridFactory::Instance().Register(std::make_tuple(1, "VCycle", "FullWeighting", "Linear"), CreateMultigrid<1, VCycle, FullWeighting, Linear>);
	const bool register2 = MultigridFactory::Instance().Register(std::make_tuple(1, "VCycle", "FullWeighting", "Quadratic"), CreateMultigrid<1, VCycle, FullWeighting, Quadratic>);
	const bool register3 = MultigridFactory::Instance().Register(std::make_tuple(1, "VCycle", "Injection", "Linear"), CreateMultigrid<1, VCycle, Injection, Linear>);
	const bool register4 = MultigridFactory::Instance().Register(std::make_tuple(1, "VCycle", "Injection", "Quadratic"), CreateMultigrid<1, VCycle, Injection, Quadratic>);
	const bool register5 = MultigridFactory::Instance().Register(std::make_tuple(1, "FullMultigridVCycle", "FullWeighting", "Linear"), CreateMultigrid<1, FullMultigridVCycle, FullWeighting, Linear>);
	const bool register6 = MultigridFactory::Instance().Register(std::make_tuple(1, "FullMultigridVCycle", "FullWeighting", "Quadratic"), CreateMultigrid<1, FullMultigridVCycle, FullWeighting, Quadratic>);
	const bool register7 = MultigridFactory::Instance().Register(std::make_tuple(1, "FullMultigridVCycle", "Injection", "Linear"), CreateMultigrid<1, FullMultigridVCycle, Injection, Linear>);
	const bool register8 = MultigridFactory::Instance().Register(std::make_tuple(1, "FullMultigridVCycle", "Injection", "Quadratic"), CreateMultigrid<1, FullMultigridVCycle, Injection, Quadratic>);

	const bool register9 = MultigridFactory::Instance().Register(std::make_tuple(2, "VCycle", "FullWeighting", "Linear"), CreateMultigrid<2, VCycle, FullWeighting, Linear>);
	const bool register10 = MultigridFactory::Instance().Register(std::make_tuple(2, "VCycle", "FullWeighting", "Quadratic"), CreateMultigrid<2, VCycle, FullWeighting, Quadratic>);
	const bool register11 = MultigridFactory::Instance().Register(std::make_tuple(2, "VCycle", "Injection", "Linear"), CreateMultigrid<2, VCycle, Injection, Linear>);
	const bool register12 = MultigridFactory::Instance().Register(std::make_tuple(2, "VCycle", "Injection", "Quadratic"), CreateMultigrid<2, VCycle, Injection, Quadratic>);
	const bool register13 = MultigridFactory::Instance().Register(std::make_tuple(2, "FullMultigridVCycle", "FullWeighting", "Linear"), CreateMultigrid<2, FullMultigridVCycle, FullWeighting, Linear>);
	const bool register14 = MultigridFactory::Instance().Register(std::make_tuple(2, "FullMultigridVCycle", "FullWeighting", "Quadratic"), CreateMultigrid<2, FullMultigridVCycle, FullWeighting, Quadratic>);
	const bool register15 = MultigridFactory::Instance().Register(std::make_tuple(2, "FullMultigridVCycle", "Injection", "Linear"), CreateMultigrid<2, FullMultigridVCycle, Injection, Linear>);
	const bool register16 = MultigridFactory::Instance().Register(std::make_tuple(2, "FullMultigridVCycle", "Injection", "Quadratic"), CreateMultigrid<2, FullMultigridVCycle, Injection, Quadratic>);
}

void UnRegister()
{
	const bool unregister1 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "VCycle", "FullWeighting", "Linear"));
	const bool unregister2 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "VCycle", "FullWeighting", "Quadratic"));
	const bool unregister3 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "VCycle", "Injection", "Linear"));
	const bool unregister4 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "VCycle", "Injection", "Quadratic"));
	const bool unregister5 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "FullMultigridVCycle", "FullWeighting", "Linear"));
	const bool unregister6 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "FullMultigridVCycle", "FullWeighting", "Quadratic"));
	const bool unregister7 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "FullMultigridVCycle", "Injection", "Linear"));
	const bool unregister8 = MultigridFactory::Instance().Unregister(std::make_tuple(1, "FullMultigridVCycle", "Injection", "Quadratic"));

	const bool unregister9 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "VCycle", "FullWeighting", "Linear"));
	const bool unregister10 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "VCycle", "FullWeighting", "Quadratic"));
	const bool unregister11 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "VCycle", "Injection", "Linear"));
	const bool unregister12 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "VCycle", "Injection", "Quadratic"));
	const bool unregister13 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "FullMultigridVCycle", "FullWeighting", "Linear"));
	const bool unregister14 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "FullMultigridVCycle", "FullWeighting", "Quadratic"));
	const bool unregister15 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "FullMultigridVCycle", "Injection", "Linear"));
	const bool unregister16 = MultigridFactory::Instance().Unregister(std::make_tuple(2, "FullMultigridVCycle", "Injection", "Quadratic"));
}

